import com.cos.lession51.proxy.*;
import org.junit.Test;
import org.springframework.cglib.proxy.Enhancer;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

/**
 * @author: COS
 * @time: 2022/3/4 15:03
 * @description:
 */
public class InvocationProxyDemo {
    /**
     * @author: COS
     * @return:
     * @time: 2022/3/4 15:05
     * @description: 基于实现接口
     * 目标类必须是有实现的接口存在
     * 动态代理的目的,生成一个代理类,通过这个代理类,来完成核心功能和辅助功能
     * <p>
     * 帮我们处理 事务 日志 等等辅助功能
     */
    @Test
    public void jdk() throws InterruptedException {
        //1 目标业务 对象
        FangDongImpl zf = new FangDongImpl();
        //2 InvocationHandler 设置代理类的核心业务,和辅助的业务功能
        InvocationHandler handler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //method 代理的方法对象
                //args 方法参数
                //辅助的功能,有没有都不影响主要业务的实现
                System.out.println("xxxx房源");
                System.out.println("带人上房,介绍房间,推销租房,买房");
                //调用目标对象的方法 通过反射来调用目标对象的核心功能丰富
                //核心业务
                Object invoke = method.invoke(zf, args);
                return invoke;
            }
        };
        //3 Proxy类来动态创建对应的代理类
        ZuFang o = (ZuFang) Proxy.newProxyInstance(
                InvocationProxyDemo.class.getClassLoader(),//代理类本身的类加载器
                zf.getClass().getInterfaces(),//1.为了约束生成出来的代理类方法,提供接口信息,让代理类和目标类实现相同的接口.
                //2.代理类和目标类都是实现了相同的接口,利用多态,使用接口引用来接受代理类的实例,进而调用方法
                handler//添加上辅助功能和调用核心业务的Handler
        );
        //用户 不想调用核心业务又去调用辅助功能的业务
        //通过生成出来的代理类,调用核心功能和辅助功能
        //4 运行执行
        o.zuFang();
    }


    @Test
    public void t1() {
//        FangDongImpl zf = new FangDongImpl();
//        for (Class<?> anInterface : zf.getClass().getInterfaces()) {
//            for (Method method : anInterface.getMethods()) {
//                System.out.println(method.getName());
//                System.out.println(Arrays.toString(method.getParameters()));
//            }
//        }
//        Method zf1 = zf.getClass().getMethod("zf");
//        zf1.invoke(zf);
    }


    public Object proxy(String path) throws Exception {
        //1 目标业务 对象 使用反射来创建
        Class<?> aClass = Class.forName(path);
        Object c = aClass.newInstance();
        //2 InvocationHandler 设置代理类的核心业务,和辅助的业务功能
        InvocationHandler handler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //辅助的功能,有没有都不影响主要业务的实现
                System.out.println("房源街道上拉人");
                System.out.println("带人上房,介绍房间,推销租房,买房");
                //核心业务
                Object invoke = method.invoke(c, args);
                return invoke;
            }
        };
        //3 Proxy类来动态创建对应的代理类
        Object o = Proxy.newProxyInstance(InvocationProxyDemo.class.getClassLoader(), aClass.getInterfaces(), handler);
        //4 把生成的代理类返回出去
        return o;
    }
    /**
     *
     * @author: COS
     * @return:
     * @time: 2022/3/4 17:03
     * @description:
     * 基于继承关系
     */
    @Test
    public void cglibDemo(){
        //1 目标对象 核心业务
        FangDong fd = new FangDong();
        //2 Enhancer 设置要的代理参数 设置父类信息
        Enhancer e = new Enhancer();
        //设置父类参数  提供父类的类对象
        e.setSuperclass(ZuFangDong.class);
        //3 通过Enhancer对象callback回调方法 实现辅助功能和核心功能的调用
        //注意这里使用的是 spring包里面的InvocationHandler
        e.setCallback(new org.springframework.cglib.proxy.InvocationHandler() {
            @Override
            public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                //method 代理的方法对象
                //args 方法参数
                //辅助的功能,有没有都不影响主要业务的实现
                System.out.println("xxxx房源");
                System.out.println("带人上房,介绍房间,推销租房,买房");
                //调用目标对象的方法 通过反射来调用目标对象的核心功能丰富
                //核心业务
                Object invoke = method.invoke(fd, objects);
                return invoke;
            }
        });
        //4 通过Enhancer创建动态代理
        //使用父类来接受
//        ZuFangDong o = (ZuFangDong) e.create();
        ZuFangDong o= (ZuFangDong) e.create();
        //5 调用方法
        o.zuFang();
    }
//ClassCastException 类型转换异常


    @Test
    public void testProxy() throws Exception {
        ZuFang proxy1 = (ZuFang) proxy("com.cos.lession51.proxy.FangDongImpl");
        proxy1.zuFang();

        System.out.println("=====================伟大的分隔符========================");
        ZuFang proxy2 = (ZuFang) proxy("com.cos.lession51.proxy.FangDongImpl2");
        proxy2.zuFang();
        System.out.println("=====================伟大的分隔符========================");

        Wahaha proxy3 = (Wahaha) proxy("com.cos.lession51.proxy.WahahaImpl");
        proxy3.show();

    }

}
